using System;
using System.Web;
using System.Web.UI.HtmlControls;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Security.Permissions;
using System.Web.UI.Design;
using System.Text;
using System.Collections.Generic;

namespace Heckel.EasyTools.Diagramming
{
    public enum TextPosition
    {
        BelowImage = 0,
        CenteredOnImage = 1
    }

    [ToolboxData("<{0}:DiagramNode runat=server></{0}:DiagramNode>")]
    internal class InternalDiagramNode : CompositeControl, ICallbackEventHandler, INamingContainer
    {
        private NodeDetailsEventArgs nodeDoubleClicked;
        private NodeDetailsEventArgs nodeClicked;
        private NodeDetailsEventArgs nodeDeleteClicked;

        private string uid
        {
            get { return ((DiagramContainer)Parent).UniqueDiagramIdentifier; }
        }

        public virtual int NodeUniqueIdentifier
        {
            get
            {
                if (ViewState["_nodeUniqueIdentifier"] != null)
                    return (int)ViewState["_nodeUniqueIdentifier"];
                return -1;
            }
            set { ViewState["_nodeUniqueIdentifier"] = value; }
        }

        public virtual bool LockChildrenToXPlaneOnDrag
        {
            get
            {
                if (ViewState["_lockChildrenToXPlaneOnDrag"] == null)
                    return false;
                return (bool)ViewState["_lockChildrenToXPlaneOnDrag"];
            }

            set { ViewState["_lockChildrenToXPlaneOnDrag"] = value; }
        }

        public virtual bool LockChildrenToYPlaneOnDrag
        {
            get
            {
                if (ViewState["_lockParentToYPlaneOnDrag"] == null)
                    return false;
                return (bool)ViewState["_lockParentToYPlaneOnDrag"];
            }

            set { ViewState["_lockParentToYPlaneOnDrag"] = value; }
        }

        public virtual bool AutoSnapChildrenBelow
        {
            get
            {
                if (ViewState["_autoSnapChildrenBelow"] == null)
                    return false;
                return (bool)ViewState["_autoSnapChildrenBelow"];
            }

            set { ViewState["_autoSnapChildrenBelow"] = value; }
        }

        public TextPosition TextPlacement
        {
            get { return (TextPosition)(ViewState["_textPlacement"] ?? TextPosition.BelowImage); }
            set { ViewState["_textPlacement"] = value; }
        }

        public bool DraggingEnabled
        {
            get { return (bool)(ViewState["_draggingEnabled"] ?? true); }
            set { ViewState["_draggingEnabled"] = value; }
        }

        public bool DrawParentLines
        {
            get { return (bool)(ViewState["_drawParentLines"] ?? true); }
            set { ViewState["_drawParentLines"] = value; }
        }

        public bool DrawChildLines
        {
            get { return (bool)(ViewState["_drawChildLines"] ?? true); }
            set { ViewState["_drawChildLines"] = value; }
        }

        public virtual int XPos
        {
            get
            {
                if (ViewState["_xPos"] != null)
                    return (int)ViewState["_xPos"];

                return 0;
            }
            set
            {
                ViewState["_xPos"] = value;
            }
        }

        public virtual int YPos
        {
            get
            {
                if (ViewState["_yPos"] != null)
                    return (int)ViewState["_yPos"];

                return 0;
            }
            set
            {
                ViewState["_yPos"] = value;
            }
        }

        public virtual string NodeImageUrl
        {
            get
            {
                if (ViewState["_nodeImageUrl"] != null)
                    return ViewState["_nodeImageUrl"].ToString();
                return "";
            }
            set { ViewState["_nodeImageUrl"] = value; }
        }

        public virtual string DeleteNodeCssClass
        {
            get
            {
                if (ViewState["_deleteNodeCssClass"] == null)
                    return "";

                return ViewState["_deleteNodeCssClass"].ToString();
            }
            set { ViewState["_deleteNodeCssClass"] = value; }
        }

        public virtual string DetailsButtonText
        {
            get
            {
                if (ViewState["_detailsButtonText"] == null)
                    return "";

                return ViewState["_detailsButtonText"].ToString();
            }
            set { ViewState["_detailsButtonText"] = value; }
        }

        public virtual CallBackType LastCallbackType
        {
            get
            {
                if (ViewState["_lastCallBackType"] == null)
                    return CallBackType.Undefined;
                else
                    return (CallBackType)ViewState["_lastCallBackType"];
            }
            set { ViewState["_lastCallBackType"] = value; }
        }

        public virtual string NodeText
        {
            get
            {
                if (ViewState["_nodeText"] != null)
                {
                    return ViewState["_nodeText"].ToString();
                }
                else
                {
                    return "";
                }
            }
            set { ViewState["_nodeText"] = value; }
        }

        public virtual string NodeDescription
        {
            get
            {
                if (ViewState["_nodeDescription"] != null)
                {
                    return ViewState["_nodeDescription"].ToString();
                }
                else
                {
                    return "";
                }
            }
            set { ViewState["_nodeDescription"] = value; }
        }

        public virtual string NodeID
        {
            get
            {
                if (ViewState["_nodeID"] != null)
                    return ViewState["_nodeID"].ToString();
                return "";
            }
            set
            {
                ViewState["_nodeID"] = value;
            }
        }

        internal virtual List<string> ParentOfIds
        {
            get
            {
                if (ViewState["_parentOfIds"] != null)
                {
                    List<DiagramNode> getChildren =
                        ((DiagramContainer)Parent).AllNodes.FindAll(
                        new Predicate<DiagramNode>(delegate(DiagramNode dn)
                        {
                            return dn.ChildOfIds.Contains(NodeID);
                        }));

                    List<string> currentParent = (List<string>)ViewState["_parentOfIds"];

                    foreach (DiagramNode gn in getChildren)
                        if (!currentParent.Contains(gn.NodeID))
                            currentParent.Add(gn.NodeID);

                    return (List<string>)ViewState["_parentOfIds"];
                }
                return new List<string>();
            }
            set
            {
                ViewState["_parentOfIds"] = value;
            }
        }

        public void AddNode(InternalDiagramNode node)
        {
            this.ParentOfIds.Add(node.NodeID);
            node.ChildOfIds.Add(this.NodeID);
        }

        internal virtual List<string> ChildOfIds
        {
            get
            {
                if (ViewState["_childOfIds"] != null)
                {
                    List<DiagramNode> getParents =
                            ((DiagramContainer)Parent).AllNodes.FindAll(
                            new Predicate<DiagramNode>(delegate(DiagramNode dn)
                            {
                                return dn.ParentOfIds.Contains(NodeID);
                            }));

                    List<string> currentChild = (List<string>)ViewState["_childOfIds"];

                    foreach (DiagramNode gn in getParents)
                        if (!currentChild.Contains(gn.NodeID))
                            currentChild.Add(gn.NodeID);

                    return (List<string>)ViewState["_childOfIds"];
                }

                return new List<string>();
            }
            set
            {
                ViewState["_childOfIds"] = value;
            }
        }

        public string NodeLineColor
        {
            get
            {
                if (ViewState["_nodeLineColor"] == null)
                    return ((DiagramContainer)Parent).GlobalLineColor;
                else if (ViewState["_nodeLineColor"].ToString() == "")
                    return ((DiagramContainer)Parent).GlobalLineColor;
                else
                    return ViewState["_nodeLineColor"].ToString();
            }
            set
            {
                ViewState["_nodeLineColor"] = value;
            }
        }

        public int NodeLinePixelWidth
        {
            get
            {
                if (ViewState["_nodeLinePixelWidth"] == null)
                    return ((DiagramContainer)Parent).GlobalLinePixelWidth;
                else if ((int)ViewState["_nodeLinePixelWidth"] == -1)
                    return ((DiagramContainer)Parent).GlobalLinePixelWidth;
                else
                    return (int)ViewState["_nodeLinePixelWidth"];
            }
            set
            {
                ViewState["_nodeLinePixelWidth"] = value;
            }
        }

        public LineType NodeLineType
        {
            get
            {
                if (ViewState["_nodeLineType"] == null)
                    return (LineType)((DiagramContainer)Parent).GlobalLineType;
                else if ((LineType)ViewState["_nodeLineType"] == LineType.Undefined)
                    return (LineType)((DiagramContainer)Parent).GlobalLineType;
                else
                    return (LineType)ViewState["_nodeLineType"];
            }
            set //for now, disable this -- canot get it to work nicely integrated mode
            {
                ViewState["_nodeLineType"] = value;
            }
        }

        public LineDecoration NodeLineDecoration
        {
            get
            {
                if (ViewState["_nodeLineDecoration"] == null)
                    return (LineDecoration)((DiagramContainer)Parent).GlobalLineDecoration;
                else if ((LineDecoration)ViewState["_nodeLineDecoration"] == LineDecoration.Undefined)
                    return (LineDecoration)((DiagramContainer)Parent).GlobalLineDecoration;
                else
                    return (LineDecoration)ViewState["_nodeLineDecoration"];
            }
            set
            {
                ViewState["_nodeLineDecoration"] = value;
            }
        }

        public InternalDiagramNode(string nodeImageUrl, string serverText, string serverDescription,
                                string serverID, int serverDBID, int xPos, int yPos,
                                List<string> parentOfIds, List<string> childOfIds)
        {
            NodeUniqueIdentifier = serverDBID;
            NodeImageUrl = nodeImageUrl;
            NodeText = serverText;
            NodeDescription = serverDescription;
            NodeID = serverID;
            XPos = xPos;
            YPos = yPos;
            ParentOfIds = parentOfIds;
            ChildOfIds = childOfIds;
        }

        private void populateAllAttachedParentNodes(DiagramNode dnode, ref Dictionary<string, List<string>> allPDependencyIds, ref Dictionary<string, List<string>> allCDependencyIds)
        {
            foreach (string pid in dnode.ParentOfIds)
            {
                if (!allPDependencyIds.ContainsKey(dnode.NodeID))
                    allPDependencyIds.Add(dnode.NodeID, new List<string>());

                allPDependencyIds[dnode.NodeID].Add(pid);

                DiagramNode pnode =
                    ((DiagramContainer)Parent).AllNodes.Find(
                    new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == pid; }));

                //if (pnode.ParentOfIds.Count > 0)
                //{
                if (!allPDependencyIds.ContainsKey(pnode.NodeID))
                    allPDependencyIds.Add(pnode.NodeID, new List<string>());

                if (!allCDependencyIds.ContainsKey(pnode.NodeID))
                    allCDependencyIds.Add(pnode.NodeID, new List<string>());

                populateAllAttachedChildrenNodes(pnode, ref allCDependencyIds, ref allPDependencyIds);
                populateAllAttachedParentNodes(pnode, ref allPDependencyIds, ref allCDependencyIds);
                //}
            }
        }

        private void populateAllAttachedChildrenNodes(DiagramNode dnode, ref Dictionary<string, List<string>> allCDependencyIds, ref Dictionary<string, List<string>> allPDependencyIds)
        {
            foreach (string cid in dnode.ChildOfIds)
            {
                if (!allCDependencyIds.ContainsKey(dnode.NodeID))
                    allCDependencyIds.Add(dnode.NodeID, new List<string>());

                allCDependencyIds[dnode.NodeID].Add(cid);

                DiagramNode pnode =
                    ((DiagramContainer)Parent).AllNodes.Find(
                    new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == cid; }));

                //if (pnode.ChildOfIds.Count > 0)
                //{
                if (!allCDependencyIds.ContainsKey(pnode.NodeID))
                    allCDependencyIds.Add(pnode.NodeID, new List<string>());

                if (!allPDependencyIds.ContainsKey(pnode.NodeID))
                    allPDependencyIds.Add(pnode.NodeID, new List<string>());

                populateAllAttachedParentNodes(pnode, ref allPDependencyIds, ref allCDependencyIds);
                populateAllAttachedChildrenNodes(pnode, ref allCDependencyIds, ref allPDependencyIds);
                //}
            }
        }

        private HtmlButton detailsButton;

        protected override void CreateChildControls()
        {
            if (!Page.IsCallback)
            {
                StringBuilder dragFunctions = ((DiagramContainer)Parent).allDragging;

                //int ux = ((DiagramContainer)Parent).XOffSet;
                //int bx = (int)((DiagramContainer)Parent).Width.Value + ((DiagramContainer)Parent).XOffSet;
                //int uy = ((DiagramContainer)Parent).YOffSet;
                //int by = (int)((DiagramContainer)Parent).Width.Value + ((DiagramContainer)Parent).YOffSet;

                dragFunctions.Append("var drag" + NodeID + " = document.getElementById(\"" + NodeID + "\"); ");
                if (DraggingEnabled)
                    dragFunctions.Append("Drag.init(drag" + NodeID + ", null, 0, " +
                                        ((DiagramContainer)Parent).Width.Value.ToString() + ", 0, " +
                                        ((DiagramContainer)Parent).Height.Value.ToString() + "); ");

                //"Drag.init(drag" + NodeID + ", null, parseInt(document.getElementById('" + uid + "_xStart').value), parseInt(document.getElementById('" + uid + "_xOffSet').value), parseInt(document.getElementById('" + uid + "_yStart').value), parseInt(document.getElementById('" + uid + "_yOffSet').value)); ");


                string _parentOfIds = "";
                //string _parentLines = "";
                foreach (string dependentNode in ParentOfIds)
                {
                    ((DiagramContainer)Parent).ZIndex--;
                    _parentOfIds += dependentNode + " ";
                    ((DiagramContainer)Parent).allParentImages.Append("<img id='" + NodeID + "ParentOf" + dependentNode + "' class='easydiagram_abs' style='visibility:hidden;z-index:" + ((DiagramContainer)Parent).ZIndex.ToString() + ";'/>" +
                                                                        "<img id='" + NodeID + "ParentOf" + dependentNode + "Arrow' class='easydiagram_abs' style='visibility:hidden;z-index:" + (((DiagramContainer)Parent).ZIndex - 1).ToString() + ";'/>");
                    ((DiagramContainer)Parent).ZIndex--;
                }
                _parentOfIds = _parentOfIds.Trim().Replace(" ", ",");

                string _childOfIds = "";
                //string _childLines = "";
                foreach (string dependentNode in ChildOfIds)
                {
                    ((DiagramContainer)Parent).ZIndex--;
                    _childOfIds += dependentNode + " ";
                    ((DiagramContainer)Parent).allChildImages.Append("<img id='" + NodeID + "ChildOf" + dependentNode + "' class = 'easydiagram_abs' style='visibility:hidden;z-index:" + ((DiagramContainer)Parent).ZIndex.ToString() + ";'/>" +
                                                                       "<img id='" + NodeID + "ChildOf" + dependentNode + "Arrow' class = 'easydiagram_abs' style='visibility:hidden;z-index:" + (((DiagramContainer)Parent).ZIndex - 1).ToString() + ";'/>");
                    ((DiagramContainer)Parent).ZIndex--;
                }
                _childOfIds = _childOfIds.Trim().Replace(" ", ",");

                dragFunctions.Append(" drag" + NodeID + ".onDrag = function(x, y) { if ( (x * y) % 2 == 0 ) { " +
                        "if (document.getElementById('" + NodeID + "InitPosition').innerHTML == '') { " +
                        "document.getElementById('" + NodeID + "InitPosition').innerHTML = x + ',' + y; } ");

                if (DrawParentLines)
                    dragFunctions.Append("drawParentLine('" + NodeID + "','" + _parentOfIds + "', x, y); ");
                
                if(DrawChildLines)
                    dragFunctions.Append("drawChildLine('" + NodeID + "', '" + _childOfIds + "', x, y); ");

                if (LockChildrenToXPlaneOnDrag || LockChildrenToYPlaneOnDrag)
                {
                    Dictionary<string, List<string>> getAllParents = new Dictionary<string, List<string>>();
                    Dictionary<string, List<string>> getAllChildren = new Dictionary<string, List<string>>();
                    foreach (string pid in ParentOfIds)
                    {
                        DiagramNode pnode =
                            ((DiagramContainer)Parent).AllNodes.Find(
                            new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == pid; }));

                        getAllParents.Add(pid, new List<string>());
                        getAllChildren.Add(pid, new List<string>());

                        foreach (string pidx in pnode.ParentOfIds)
                        {
                            if (!pnode.AutoSnapChildrenBelow)
                                getAllParents[pid].Add(pidx);
                            //DiagramNode pnode =
                            //     ((DiagramContainer)Parent).AllNodes.Find(
                            //     new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == pidx; }));

                            //foreach (string pidxx in pnode.ParentOfIds)
                            //{
                            //
                            //}
                        }

                        foreach (string cidx in pnode.ChildOfIds)
                        {
                            DiagramNode getParentNode =
                                 ((DiagramContainer)Parent).AllNodes.Find(
                                 new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == cidx; }));

                            if (!getParentNode.AutoSnapChildrenBelow)
                                getAllChildren[pid].Add(cidx);

                            /*

                            if (!getParentNode.AutoSnapChildrenBelow &&
                                !((DiagramContainer)Parent).IsChildSnappedBelowParent(pnode, getParentNode))
                                getAllChildren[pid].Add(cidx
                             * */
                        }
                        //populateAllAttachedParentNodes(pnode, ref getAllParents, ref getAllChildren);
                        //populateAllAttachedChildrenNodes(pnode, ref getAllChildren, ref getAllParents);
                    }

                    StringBuilder allParents = new StringBuilder();
                    foreach (KeyValuePair<string, List<string>> allParentDeps in getAllParents)
                    {
                        if (allParentDeps.Value.Count > 0)
                        {
                            allParents.Append(allParentDeps.Key + ":");
                            foreach (string apx in allParentDeps.Value)
                                allParents.Append(apx + ",");
                            allParents.Append("~");
                        }
                    }

                    string getallparents = "";
                    if (allParents.Length > 0)
                    {
                        getallparents = allParents.ToString().Trim();
                        //getallparents = getallparents.Substring(0, getallparents.Length - 1);
                    }

                    StringBuilder allChildren = new StringBuilder();
                    foreach (KeyValuePair<string, List<string>> allChildDeps in getAllChildren)
                    {
                        if (allChildDeps.Value.Count > 0)
                        {
                            allChildren.Append(allChildDeps.Key + ":");
                            foreach (string apx in allChildDeps.Value)
                                allChildren.Append(apx + ",");
                            allChildren.Append("~");
                        }
                    }

                    string getallchildren = "";
                    if (allChildren.Length > 0)
                    {
                        getallchildren = allChildren.ToString().Trim();
                        //getallchildren = getallchildren.Substring(0, getallchildren.Length - 1);
                    }

                    dragFunctions.Append("drawLockedNodes('" + NodeID + "','" + _parentOfIds + "', x, y, " +
                        LockChildrenToXPlaneOnDrag.ToString().ToLower()
                        + ", " + LockChildrenToYPlaneOnDrag.ToString().ToLower() 
                        + ", " + AutoSnapChildrenBelow.ToString().ToLower()  
                        + ",'" + getallparents + "','" + getallchildren + "'); ");
                }

                dragFunctions.Append("} };  ");

                dragFunctions.Append(" drag" + NodeID + ".onDragEnd = function(x, y) { ");

                if (LockChildrenToXPlaneOnDrag || LockChildrenToYPlaneOnDrag)
                    dragFunctions.Append("SetInitPositionForAllChildren('" + _parentOfIds + "'); ");

                dragFunctions.Append("document.getElementById('" + NodeID + "InitPosition').innerHTML = x + ',' + y; " +
                                    Page.ClientScript.GetCallbackEventReference(this, "'" +
                                    ((int)CallBackType.NodeBeingRepositioned).ToString()
                                    + "' + x + '|' + y", "nodeSuccessfullyRepositioned", "null") + "; }; ");

                if (DetailsButtonText != "")
                {
                    detailsButton = new HtmlButton();
                    detailsButton.InnerText = DetailsButtonText;
                    detailsButton.Attributes.Add("onclick", Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.NodeDetailsClicked).ToString() + "' + document.getElementById('" + NodeID + "MessageText').innerHTML", "nodeDetailsClicked", "null"));
                }
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            /*
            string styling = "";
            if (this.BackColor != System.Drawing.Color.Empty && this.ForeColor != System.Drawing.Color.Empty && this.BorderColor != System.Drawing.Color.Empty)
                styling = " onmouseout = \"this.style.cursor='default'; this.style.backgroundColor='';this.style.borderRight='0px'; this.style.borderBottom='0px';\" onmouseover=\"this.style.cursor='move'; this.style.backgroundColor='" + Utils.ColorToHex(ForeColor) + "';this.style.borderRight='1px inset " + Utils.ColorToHex(BorderColor) + "';this.style.borderBottom='1px inset " + Utils.ColorToHex(BorderColor) + "'\" ";

            double tWidth = this.Width.Value;
            double tHeight = this.Height.Value;
            if (((DiagramContainer)Parent).GlobalShowDetailsButton)
            {
                //make room for button
                tWidth += 15;
                tHeight += 15;
            }

            //log for this node
            writer.Write("<div id='" + NodeID + "MessageText' style='display:none;'></div>");
            
            //data for this node
            writer.Write("<div id='" + NodeID + "Data' style='display:none;'>" + 
                          StringEnum.GetStringValue(NodeLineType) + "|" + ((int)NodeLineDecoration).ToString() + 
                          "|" + NodeLineColor + "|" + NodeLinePixelWidth.ToString() + "</div>");

            //absolute div container
            writer.Write("<div class='easydiagram_abs' title=\"" + NodeDescription + "\" style=\"margin: 3px 3px 3px 3px; z-index:2001; left: " + XPos + 
                "px; top:" + YPos + "px; width:" + tWidth.ToString() + "px;height:" + tHeight.ToString() + 
                "px;\" id=\"" + NodeID + "\"" + styling + " ondblclick = \"" + 
                Page.ClientScript.GetCallbackEventReference(this, "'" + 
                ((int)CallBackType.NodeDoubleClicked).ToString() + this.NodeUniqueIdentifier.ToString() + 
                "'", "nodeDoubleClicked", "null") + "\">");
            
            //table containing layout
            writer.Write("<div style=\"position:relative;float:left;\">");
            writer.Write("<img src='" + NodeImageUrl + "'/>");
                //serverNodeImage.RenderControl(writer);
            writer.Write("</div>");

            if (DetailsButtonText != "" || DeleteNodeCssClass != "")
            {
                writer.Write("<div style=\"position:relative;float:right\">");

                if (((DiagramContainer)Parent).GlobalShowDetailsButton)
                    if (DetailsButtonText != "")
                        detailsButton.RenderControl(writer);

                if (DeleteNodeCssClass != "")
                    writer.Write("<div style=\"position:relative;\" class=\"" + DeleteNodeCssClass + "\" onclick=\"" + Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.NodeDeleted).ToString() + "'", "nodeDeleteClicked", "null") + "\">&nbsp;</div>");

                writer.Write("</div>");
            }

            if (NodeText != "")
            {
                writer.Write("<div style='position:relative;clear:both;height:22px;'>");
                writer.Write(NodeText);
                writer.Write("</div>");
            }

            writer.Write("</div>");
            
            //dScriptHolder.RenderControl(writer);
            */
        }

        public override string ToString()
        {
            StringBuilder nodeString = new StringBuilder();
            string styling = "";
            if (this.BackColor != System.Drawing.Color.Empty && this.ForeColor != System.Drawing.Color.Empty && this.BorderColor != System.Drawing.Color.Empty)
                styling = " onmouseout = \"this.style.backgroundColor='';this.style.borderRight='0px'; this.style.borderBottom='0px';\" onmouseover=\"this.style.backgroundColor='" + Utils.ColorToHex(ForeColor) + "';this.style.borderRight='1px inset " + Utils.ColorToHex(BorderColor) + "';this.style.borderBottom='1px inset " + Utils.ColorToHex(BorderColor) + "'\" ";

            double tWidth = this.Width.Value;
            double tHeight = this.Height.Value;
            if (((DiagramContainer)Parent).GlobalShowDetailsButton)
            {
                //make room for button
                tWidth += 15;
                tHeight += 15;
            }

            //log for this node
            nodeString.Append("<div id='" + NodeID + "MessageText' style='display:none;'></div>");
            nodeString.Append("<div id='" + NodeID + "InitPosition' style='display:none;'></div>");
            nodeString.Append("<div id='" + NodeID + "DrawParentLines' style='display:none;'>" + DrawParentLines.ToString().ToLower() + "</div>");
            nodeString.Append("<div id='" + NodeID + "DrawChildLines' style='display:none;'>" + DrawChildLines.ToString().ToLower() + "</div>");
            nodeString.Append("<div id='" + NodeID + "SnapChildrenBelow' style='display:none;'>" + AutoSnapChildrenBelow.ToString().ToLower() + "</div>");
            
            //data for this node
            nodeString.Append("<div id='" + NodeID + "Data' style='display:none;'>" +
                          StringEnum.GetStringValue(NodeLineType) + "|" + ((int)NodeLineDecoration).ToString() +
                          "|" + NodeLineColor + "|" + NodeLinePixelWidth.ToString() + "</div>");

            //absolute div container
            nodeString.Append("<div class='easydiagram_abs' title=\"" + NodeDescription + "\" style=\"margin: 3px 3px 3px 3px; z-index:2001; left: " + XPos +
                "px; top:" + YPos + "px; width:" + tWidth.ToString() + "px;height:" + tHeight.ToString() +
                "px; " + (DraggingEnabled ? "cursor:move;" : "cursor:pointer;") + "\" id=\"" + NodeID + "\"" + styling + " ondblclick = \"" +
                Page.ClientScript.GetCallbackEventReference(this, "'" +
                ((int)CallBackType.NodeDoubleClicked).ToString() + this.NodeUniqueIdentifier.ToString() +
                "'", "nodeDoubleClicked", "null") + "\">");

            if (TextPlacement == TextPosition.BelowImage)
            {
                nodeString.Append("<div style=\"position:relative;float:left;\">");
                nodeString.Append("<img src='" + NodeImageUrl + "'/>");
                nodeString.Append("</div>");
            }
            else if (TextPlacement == TextPosition.CenteredOnImage && !String.IsNullOrEmpty(NodeImageUrl))
            {
                System.Net.WebClient nClient = new System.Net.WebClient();
                string imageurl = NodeImageUrl.Replace("..", "");

                if (imageurl.IndexOf("http") == -1)
                    imageurl = ((DiagramContainer)Parent).BaseUrl + imageurl;

                System.IO.MemoryStream getStream = new System.IO.MemoryStream(nClient.DownloadData(imageurl));
                System.Drawing.Bitmap getDimensions = new System.Drawing.Bitmap(getStream);

                nodeString.Append("<div style=\"width:" + (getDimensions.Width + 3).ToString() + "px;height:" + (getDimensions.Height + 3).ToString() + "px;position:relative;float:left;background-image:url('" + NodeImageUrl + "');background-position:left top; background-repeat:no-repeat;\">");
                if (NodeText != "")
                    nodeString.Append("<div style='width:100px;padding:5px;text-align:center;'>" + NodeText + "</div>");
                nodeString.Append("</div>");
            }

            if (DetailsButtonText != "" || DeleteNodeCssClass != "")
            {
                nodeString.Append("<div style=\"position:relative;float:right\">");

                /*
                if (((DiagramContainer)Parent).GlobalShowDetailsButton)
                    if (DetailsButtonText != "")
                        detailsButton.RenderControl(writer);
                */

                if (DeleteNodeCssClass != "")
                    nodeString.Append("<div style=\"position:relative;\" class=\"" + DeleteNodeCssClass + "\" onclick=\"" + Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.NodeDeleted).ToString() + "'", "nodeDeleteClicked", "null") + "\">&nbsp;</div>");

                nodeString.Append("</div>");
            }

            if (NodeText != "" && TextPlacement == TextPosition.BelowImage)
            {
                nodeString.Append("<div style='position:relative;clear:both;height:22px;width:70px;margin-left:20px'>");
                nodeString.Append(NodeText);
                nodeString.Append("</div>");
            }

            nodeString.Append("</div>");

            return nodeString.ToString();
        }

        public void RaiseCallbackEvent(String eventArgument)
        {
            string callbackString = eventArgument.Substring(1, eventArgument.Length - 1);
            switch (Convert.ToInt32(eventArgument.Substring(0, 1)))
            {
                case (int)CallBackType.NodeBeingRepositioned:
                    LastCallbackType = CallBackType.NodeBeingRepositioned;
                    string[] splitter = callbackString.Split('|');
                    ((DiagramContainer)Parent).RaiseNodeEvent(ExecutingEvent.Repositioned, new NodeRepositionEventArgs(NodeText, NodeUniqueIdentifier, Int32.Parse(splitter[0]), Int32.Parse(splitter[1])));
                    break;
                case (int)CallBackType.NodeDoubleClicked:
                    LastCallbackType = CallBackType.NodeDoubleClicked;
                    nodeDoubleClicked = new NodeDetailsEventArgs(NodeID, NodeText, NodeUniqueIdentifier, "");
                    ((DiagramContainer)Parent).RaiseNodeEvent(ExecutingEvent.DoubleClicked, nodeDoubleClicked);
                    break;
                case (int)CallBackType.NodeDetailsClicked:
                    LastCallbackType = CallBackType.NodeDetailsClicked;
                    nodeClicked = new NodeDetailsEventArgs(NodeID, NodeText, NodeUniqueIdentifier, callbackString);
                    ((DiagramContainer)Parent).RaiseNodeEvent(ExecutingEvent.DetailsClicked, nodeClicked);
                    break;
                case (int)CallBackType.NodeDeleted:
                    LastCallbackType = CallBackType.NodeDeleted;
                    nodeDeleteClicked = new NodeDetailsEventArgs(NodeID, NodeText, NodeUniqueIdentifier, callbackString);
                    ((DiagramContainer)Parent).RaiseNodeEvent(ExecutingEvent.DeleteClicked, nodeDeleteClicked);
                    break;
            }
        }

        public string GetCallbackResult()
        {
            switch (LastCallbackType)
            {
                case CallBackType.NodeBeingRepositioned:
                    return "";
                case CallBackType.NodeDoubleClicked:
                    return nodeDoubleClicked.ModalDialogueHtmlToDisplay + "##" + nodeDoubleClicked.NavigateUrl + "##" + FormatUnit(nodeDoubleClicked.ModalDialogueWidth) + "##" + FormatUnit(nodeDoubleClicked.ModalDialogueHeight) + "##" + formatScripts(nodeDoubleClicked.ScriptsToExecuteOnModalWindowShown) + "##" + formatScripts(nodeDoubleClicked.ScriptsToExecuteOnModalWindowClose);
                case CallBackType.NodeDetailsClicked:
                    return nodeClicked.ModalDialogueHtmlToDisplay + "##" + nodeClicked.NavigateUrl + "##" + FormatUnit(nodeClicked.ModalDialogueWidth) + "##" + FormatUnit(nodeClicked.ModalDialogueHeight) + "##" + formatScripts(nodeClicked.ScriptsToExecuteOnModalWindowShown) + "##" + formatScripts(nodeClicked.ScriptsToExecuteOnModalWindowClose);
                default:
                    return "";
            }
        }

        private string formatScripts(List<string> allScripts)
        {
            string fScripts = "";
            foreach (string script in allScripts)
                fScripts += script + ";";

            if (fScripts.Length > 0)
                return fScripts.Substring(0, fScripts.Length - 1);
            else
                return "";
        }

        private string FormatUnit(Unit unitToFormat)
        {
            StringBuilder fu = new StringBuilder();
            fu.Append(unitToFormat.Value.ToString());

            switch (unitToFormat.Type)
            {
                case UnitType.Percentage:
                    fu.Append("%");
                    break;
                case UnitType.Pixel:
                    fu.Append("px");
                    break;
            }

            return fu.ToString();
        }
    }
}
